
`include "common_header.verilog"

//  *************************************************************************
//  File : sat_counter_evt3.vhd
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2012 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Daniel Koehler
//  info@morethanip.com
//  *************************************************************************
//  Description : General purpose saturating error counter
//                which can accept 3 simultaneous error indications
//  Version     : $Id: sat_counter_evt3.v,v 1.1 2012/10/29 10:37:08 dk Exp $
//  *************************************************************************
module sat_counter_evt3 (

   reset,
   clk,
   clk_ena,
   inc_event,
   count_ena,
   count_rd,
   count_value);

parameter CNT_WIDTH = 22;

input   reset;                  //  asynch reset
input   clk;                    //  system clock
input   clk_ena;                //  clock enable
input   [2:0] inc_event;        //  per lane event to count, valid with clk_ena
input   count_ena;              //  allow counting (1) or ignore events (0)
input   count_rd;               //  Counter read and clear. single clock pulse, NOT masked with clk_ena!
output  [CNT_WIDTH - 1:0] count_value; //  counter current value (moving!)

wire    [CNT_WIDTH - 1:0] count_value; 

reg     [2:0] inc_event_s;              //  per lane  from STM
reg     [1:0] cnt_inc_add;              //  1..3 increment value
reg     cnt_inc;                        //  increment value is valid
reg     [CNT_WIDTH - 1:0] count_s;      //  counter
wire    [CNT_WIDTH:0] cnt_inc_add_ext;  //  extended for addition
wire    [CNT_WIDTH:0] count_next;       //  counter with carry

//  --------------------------------------------------------------------
//  accumulate 1..3 events for each lane determined in one cycle.
//  --------------------------------------------------------------------

always @(posedge reset or posedge clk)
   begin : process_1
   if (reset == 1'b 1)
      begin
      inc_event_s <= 3'b 000;	
      cnt_inc <= 1'b 0;	
      cnt_inc_add <= 2'b 00;	
      end
   else
      begin

        //  create single cycle pulse per lane.

      if (clk_ena == 1'b 1 & count_ena == 1'b 1)
         begin
         inc_event_s <= inc_event;	
         end
      else
         begin
         inc_event_s <= 3'b 000;	
         end

        //  determine increment value 1..3

      case (inc_event_s)
      3'b 001,
      3'b 010,
      3'b 100:
         begin
         cnt_inc_add <= 2'b 01;	
         end
      3'b 011,
      3'b 110,
      3'b 101:
         begin
         cnt_inc_add <= 2'b 10;	
         end
      3'b 111:
         begin
         cnt_inc_add <= 2'b 11;	
         end
      default:
         begin
         cnt_inc_add <= 2'b 00;	
         end
      endcase

      if (inc_event_s != 3'b 000)
         begin
         cnt_inc <= 1'b 1;	
         end
      else
         begin
         cnt_inc <= 1'b 0;	
         end

      end
   end

//  implement saturating counter
//  ----------------------------
assign count_value = count_s; 

assign cnt_inc_add_ext[CNT_WIDTH:2] = {(CNT_WIDTH - 1){1'b 0}}; 
assign cnt_inc_add_ext[1:0]         = cnt_inc_add; 
assign count_next                   = {1'b 0, count_s} + cnt_inc_add_ext; 

always @(posedge reset or posedge clk)
   begin : process_2
   if (reset == 1'b 1)
      begin
      count_s <= {(CNT_WIDTH){1'b 0}};	
      end
   else
      begin
      if (count_rd == 1'b 1)
         begin
         count_s[CNT_WIDTH - 1:2] <= {(CNT_WIDTH-2){1'b 0}};	
         count_s[1:0] <= cnt_inc_add;	//  don't loose count while reading
         end
      else if (cnt_inc == 1'b 1 )
         begin
         if (count_next[CNT_WIDTH] == 1'b 0)
            begin
            count_s <= count_next[CNT_WIDTH - 1:0];	
            end
         else
            begin
            count_s <= {(CNT_WIDTH){1'b 1}};	//  saturate
            end
         end
      end
   end


endmodule // module sat_counter_evt3

